﻿                 # Scene 2D class - creates a scene from a canvas
# Container for a list of shapes                           
class window.Scene2D extends Observable
    constructor: (@canvasId) ->
        super        
        @canvas = document.getElementById(@canvasId);
        @context = @canvas.getContext("2d");
        @shapes = []
        animation.bind(this, @animationLoop);
    
    # add a shape to the scene
    add : (shape) ->               
        @shapes.push(shape)
        shape.context = @context 
        shape.scene = this
        @shapes = @shapes.sort( 
            (a,b)->
                if a.zIndex<b.zIndex then 1
                else if a.zIndex>b.zIndex then -1 else 0
        )
      
    #remove a shape from the scene  
    remove : (shape) ->
        @shapes.find(
         (elem, index, arr) ->
            if shape is elem
                elem.context = null 
                elem.scene = null
                arr.splice(index,1)
        )        
        
    # event from animation object
    # this is triggered all the time
    # we go through all shapes, and recompute their position
    # we redraw the scene
    animationLoop : (self, appTime) ->
        if self.lastTime 
            dt = (appTime - self.lastTime) / 1000
            self.shapes.each((elem,index,arr)->
                # get force
                force = elem.getComposedForce()
                # compute velocity
                elem.velocity.dx += force.ax * dt
                elem.velocity.dy += force.ay * dt
                
                # compute location                
                if typeof elem.location is "function"
                    location = elem.location();
                else location = elem.location
                newx = location.x + elem.velocity.dx * dt
                eventArgs = 
                    shape : elem
                    x : newx
                    y : location.y
                    width : elem.size.width
                    height : elem.size.height
                    time : appTime
                cancel = not elem.notify("onmoving",eventArgs)
                if not cancel
                    if typeof elem.location is "function"
                        elem.location(newx, null)                    
                    else elem.location.x = newx
                    
                newy = location.y + elem.velocity.dy * dt
                eventArgs = 
                    shape : elem
                    x : location.x
                    y : newy
                    width : elem.size.width
                    height : elem.size.height
                    time : appTime
                cancel = not elem.notify("onmoving",eventArgs); 
                if not cancel
                    if typeof elem.location is "function"
                        elem.location(null, newy)                    
                    else elem.location.y = newy                                       
                true
            );                    
        self.lastTime = appTime
        # trigger scene redraw
        self.invalidate()
       
    # clears the scene and redraws it
    # in the future we will need to update this such that we only redraw what changess
    invalidate : () ->
        @context.clearRect(0,0, @canvas.width, @canvas.height)
        @shapes.each((elem,index,arr)->    
            elem.draw()
        )
    getShapeAtPosition : (x,y) ->
        shape = null
        @shapes.each((elem,index,arr)->
            if elem.location.x<x and elem.location.x+elem.size.width>x and elem.location.y<y and elem.location.y+elem.size.height>y
                if not shape or shape.zIndex<elem.zIndex
                    shape = elem            
        )
        shape
        
# Shape2D - base class for all shapes, containing basic properties and methods
class window.Shape2D extends Observable
    constructor:() ->
        super
        @type = "shape-2d"
        @id = (new Date()).getTime()
        @name = "Shape_"+@id
        # the parent scene and context
        @scene = null
        @context = null
        # rotation - allow to rotate objects
        # we will need to think this better... at this time it will not be implemented
        # or it will be implemented at the concrete class level
        @rotation = 0
        # list of forces, or rather accelerations, imposed on the shape
        # use addForce, removeForce to set them
        @forces = []
        # current velocity of the shape        
        @velocity = 
            dx : 0
            dy: 0
        # current position of the shape
        @location = 
            x : 0
            y: 0
        # current  size of the shape
        @size = 
            width : 0
            height : 0
        # not used for now... it will specify whether a shape needs redrawing or not
        @dirty = false
        # the z index of the shape - used to specify which shape is on top
        @zIndex = 0
        
    move : (x, y) ->
        if not @location.x is x or not @location.y is y
            @dirty = true
        @location.x = x
        @location.y = y        
    moveX : (x) ->
        if not @location.x is x
            @dirty = true
        @location.x = x
    moveY : (y) ->
        if not @location.x is y
            @dirty = true
        @location.y = y
    # adds a force / acceleration to the shape 
    addForce : (id, ax, ay) ->
        force = 
            id : id
            ax : ax
            ay : ay
        @forces.push(force)   
        force
        
    # adds a force / acceleration to the shape 
    getForce : (id) ->
        force = null;
        @forces.find((elem,index,arr)->
            if elem.id is id
                force = elem
        );
        if force
           force;
        else @addForce(id,0,0) 
        
    setForceAx : (id,ax) ->
        force = null;
        @forces.find((elem,index,arr)->
            if elem.id is id
                elem.ax = ax;
        );                           
    setForceAy : (id,ay) ->
        force = null;
        @forces.find((elem,index,arr)->
            if elem.id is id                
                elem.ay = ay;
        );                           
        
    # removes an acceleration from the shape        
    removeForce : (id) ->
        @forces.find((elem,index,arr)->
            if elem.id is id
                arr.splice(index,1)
        );
        true
        
    # composes all added accelerations to get the overall value
    # we simply add the x and y components
    getComposedForce : () ->
        force = 
            id : "composed"
            ax : 0
            ay : 0
        @forces.each((elem,index,arr)->
            if elem.ax
                force.ax += elem.ax;
            if elem.ay
                force.ay += elem.ay;
        )
        force             
           
    # specifies if this shape intersects another shape situated at the given location and having the given size         
    # basically it is a rectangle intersection check
    intersects : (location,size) ->
        minAx = @location.x
        minAy = @location.y
        maxAx = @location.x + @size.width
        maxAy = @location.y + @size.height
		
        minBx = location.x
        minBy = location.y
        maxBx = location.x + size.width
        maxBy = location.y + size.height
		
        aLeftOfB = maxAx < minBx
        aRightOfB = minAx > maxBx
        aAboveB = minAy > maxBy
        aBelowB = maxAy < minBy
        !( aLeftOfB || aRightOfB || aAboveB || aBelowB )
    
    getBoundary : () ->
        size = @size
        location = @location
        if typeof location is "function"
            location = @location()        
        [location.x,location.y,location.x+size.width,location.y+size.height]
        
    boundaryIntersects : (shape) ->
        b1 = @getBoundary()
        b2 = shape.getBoundary()
        minAx = b1[0]
        minAy = b1[1]
        maxAx = b1[2]
        maxAy = b1[3]
		
        minBx = b2[0]
        minBy = b2[1]
        maxBx = b2[2]
        maxBy = b2[3]
		
        aLeftOfB = maxAx < minBx
        aRightOfB = minAx > maxBx
        aAboveB = minAy > maxBy
        aBelowB = maxAy < minBy
        !( aLeftOfB || aRightOfB || aAboveB || aBelowB )
        
    getCollidingShapes : () ->        
        collidingShapes = []
        self = this
        if @scene
            @scene.shapes.each((elem,index,arr)->                
                if not (elem is self)
                   if self.boundaryIntersects(elem)
                        collidingShapes.push(elem) 
            )
        collidingShapes
        
    # draws the shape
    # this needs to be overloaded by the subclasses
    draw : () ->
    

# GraphicShape2D - class used to be a super class for drawing shapes - shapes that 
# we draw with lines and colors (lines, rectangles, circles, ellipses, etc)
class window.GraphicShape2D extends Shape2D
   constructor : ->          
          super 
          @type = "graphics-shape-2d"
          # border width and color
          @stroke = 
            width : 1
            color : "#000"
          # fill enable and color
          @fill = 
            enabled : false
            color : "#fff"    
    # sets the filling color if neccesary
    setFillStyles : () ->
        if @fill.enabled			
            @context.fillStyle = @fill.color
        else
            @context.fillStyle = null
            
    # sets the border colors to the canvas 			
    setStrokeStyles : () -> 
        @context.lineWidth = @stroke.width
        @context.strokeStyle = @stroke.color			
        
    # sets fill and stroke styles
    setStyles : () ->
        @setStrokeStyles();
        @setFillStyles();
        true
      
    # executes the draw or fill depending on the current settings  
    executeDraw : () ->        
        @context.stroke();
        if @fill.enabled
            @context.fill();
         
# Rectangle2D - class for creating a rectangle
class window.Rectangle2D extends GraphicShape2D 
    constructor : (x, y, width, height) ->        
        super
        @type = "rectangle-2d"
        # set location and size
        @location.x = x
        @location.y = y
        @size.width = width
        @size.height = height
        
        # set border radius
        @borderRadius = 0
        
    # draw the rectangle
    # basically we set the GraphicShape2D styles, we draw the shape
    # we call GraphicShape2D executeDraw to fill or stroke
    draw : () ->    
        @setStyles();
        @context.beginPath();
        if(@borderRadius>0)
	        @context.roundRect(@location.x,@location.y,@size.width,@size.height,@borderRadius);
        else @context.rect(@location.x,@location.y,@size.width,@size.height);
        @context.closePath();
        @executeDraw();
        
# Ellipse2D - class for creating an ellipse
class window.Ellipse2D extends GraphicShape2D 
    constructor : (x, y, radiusX, radiusY) ->        
        super
        @type = "ellipse-2d"
        # set location and size        
        @location.x = x-radiusX
        @location.y = y-radiusY
        @size.width = 2 * radiusX
        @size.height = 2 * radiusY 
        @center = 
            x : x
            y : y
        @radiusX = radiusX
        @radiusY = radiusY
            
    # draw the ellipse
    # basically we set the GraphicShape2D styles, we draw the shape
    # we call GraphicShape2D executeDraw to fill or stroke
    draw : () -> 
        if @context
            @center = 
                x : @location.x + @radiusX
                y : @location.y + @radiusY
            @setStyles();            
            @context.beginPath();        
            lx = @center.x - @radiusX
            rx = @center.x + @radiusX
            ty = @center.y - @radiusY
            uy = @center.y + @radiusY
            magic = 0.551784;
            xmagic = magic * @radiusX
            ymagic = @radiusY * magic            
            @context.moveTo(@center.x,ty);
            @context.bezierCurveTo(@center.x+xmagic,ty,rx,@center.y-ymagic,rx,@center.y);
            @context.bezierCurveTo(rx,@center.y+ymagic,@center.x+xmagic,uy,@center.x,uy);
            @context.bezierCurveTo(@center.x-xmagic,uy,lx,@center.y+ymagic,lx,@center.y);
            @context.bezierCurveTo(lx,@center.y-ymagic,@center.x-xmagic,ty,@center.x,ty);
            @context.closePath()
            @executeDraw()  

# Circle2D - class for creating a circle. Due to how the canvas draws this, we will not
# inherit from ellipse as we would normally do
class window.Circle2D extends GraphicShape2D           
    constructor : (x, y, radius) ->        
        super
        @type = "circle-2d"
        # set location and size
        @location.x = x-radius
        @location.y = y-radius
        @size.width = 2 * radius
        @size.height = 2 * radius
        @center = 
            x : x
            y : y
        @radius = radius                        
    # draw the circle
    draw : () ->
        if @context
            @context.beginPath()
            @context.arc(@location.x+@radius, @location.y+@radius, @radius, 0, 2 * Math.PI, false)		
            @executeDraw()
		    
# Line2D - class for creating a line
# This class could also override the intersecs function to make it more precise. I am thinking
# to consider a geometrical collition detection here... Not sure if we can do it though, due to 
# the extensibility we want to maintain.
class window.Line2D extends GraphicShape2D
    constructor : (x, y, width, height) ->        
        super
        @type = "line-2d"
        # set location and size
        @location.x = x
        @location.y = y
        @size.width = width
        @size.height = height        
    # draw the line    
    draw : () ->
        if @context
            @center = 
                x : @location.x + @radius
                y : @location.y + @radius
            @setStyles()
            @context.beginPath()
            @context.moveTo(@location.x,@location.y)
            @context.lineTo(@location.x+@size.width,@location.y+@size.height)
            @context.closePath()
            @executeDraw()

# Arrow2D - class for creating a line with an arrow on one of the ends
class window.Arrow2D extends GraphicShape2D
    constructor : (x, y, width, height) ->        
        super
        @type = "arrow-2d"
        # set location and size
        @location.x = x
        @location.y = y
        @size.width = width
        @size.height = height
        # size of the arrow lines
        @as = Math.sqrt(height * height + width*width) / 20
        #angle of the arrow lines
        @angle = Math.atan2(height,width);
    draw : () ->
        if @context
            @setStyles()
            @context.beginPath()
            @context.moveTo(@location.x,@location.y);
            @context.lineTo(@location.x+@size.width,@location.y+@size.height);
            @context.lineTo(@location.x+@size.width-@as*Math.cos(@angle-Math.PI/6),@location.y+@size.height-@as*Math.sin(@angle-Math.PI/6))
            @context.moveTo(@location.x+@size.width,@location.y+@size.height);
            @context.lineTo(@location.x+@size.width-@as*Math.cos(@angle+Math.PI/6),@location.y+@size.height-@as*Math.sin(@angle+Math.PI/6))
            @executeDraw()

# PolyLine2D class used to handle an object formed by a variable number of connected lines
# Due to the specifics of this implementation, forces and velocity does not work on
# this object. Further thought is required to have this. We will probably need to 
# either make location as a function (property), or to make a move function that this 
# class will need to override.
# This class will also need to override the intersects function to make it more precise
class window.PolyLine2D extends GraphicShape2D
    constructor : (points) ->
        super
        @type = "polyline-2d"
        #check if points is an array
        @points = new Array()
        if typeof points is "object" and points.length
            self = this;
            @location.x = null
            @location.y = null
            @size.width = 0
            @size.height = 0
            @points = []  
            # set up all points
            # check the points are valid - have x and y coordinates
            # compute the location and size of the object from the points          
            points.each( (elem, index, array)->
                if elem and elem.x and elem.y and typeof elem.x is "number" and typeof elem.y is "number"
                    self.points.push( elem );
                    if !self.location.x or self.location.x>elem.x
                        self.location.x = elem.x        
                    if !self.location.y or self.location.x>elem.y
                        self.location.y = elem.y
                    if index>0 and Math.abs(array[index-1].x-elem.x)>self.size.width
                        self.size.width = Math.abs(array[index-1].x-elem.x)
                    if index>0 and Math.abs(array[index-1].y-elem.y)>self.size.height
                        self.size.height = Math.abs(array[index-1].y-elem.y)
            )
            
    # returns the boundary of a polygon    
    getBoundary : () ->        
        if !@points or !@points.length
            [0,0,0,0]
        else
            minx=@points[0].x
            maxx=@points[0].x
            miny=@points[0].y
            maxy=@points[0].y
            self = this
            @points.each((elem,index,arr)->
                if elem.x < minx
                    minx = elem.x
                if elem.x > maxx
                    maxx = elem.x
                if elem.y < miny
                    miny = elem.y
                if elem.y > maxy
                    maxy = elem.y
            )
            [minx,miny,maxx,maxy]
            
    # draw the polyline
    draw : () ->
        if @context
            @setStyles()
            @context.beginPath()
            self = this
            @points.each((elem, index, array)->                
                if index is 0
                    self.context.moveTo(elem.x,elem.y)
                else
                    self.context.lineTo(elem.x,elem.y)                    
            )
            @context.closePath()        
            @executeDraw()
            
# Image2D class - used for drawing images
class window.Image2D extends Shape2D
    constructor : (x,y,width,height, image) ->
        super
        @type = "image-2d"
        # set location and size
        @location.x = x
        @location.y = y
        @size.width = width
        @size.height = height
        
        # set the image source
        @changeImage(image)        
    # sets the image source to an Image type or to an image url    
    changeImage : (image) ->
        if typeof image is "object" and image.tagName is "IMG"
            @image = image
        else
            if typeof image is "string"
                self = this
                img = new Image()            
                img.onload = () ->
                    self.image = this
                img.src = image;
            else
                false
    #draw the image
    draw : () ->
        if @image and @context
            @context.drawImage(@image, @location.x, @location.y, @size.width, @size.height)
            
# PartialImage2D class - used for drawing images
class window.PartialImage2D extends Shape2D
    constructor : (x,y,width,height, image) ->
        super
        @type = "image-2d"
        # set location and size
        @location.x = x
        @location.y = y
        @size.width = width
        @size.height = height
        @clippingRectangle = 
            x : 0
            y : 0
            width : @size.width
            height : @size.height
        
        # set the image source
        @changeImage(image)        
    # sets the image source to an Image type or to an image url    
    changeImage : (image) ->
        if typeof image is "object" and image.tagName is "IMG"
            @image = image
        else
            if typeof image is "string"
                self = this
                img = new Image()            
                img.onload = () ->
                    self.image = this
                img.src = image;
            else
                false
                
    setClippingRectangle : (x,y,width,height) ->
        @clippingRectangle = 
                x : x
                y : y
                width : width
                height : height
                
    #draw the image
    draw : () ->
        if @image and @context
            @context.drawImage(@image, @clippingRectangle.x, @clippingRectangle.y, @clippingRectangle.width, @clippingRectangle.height, @location.x, @location.y, @size.width, @size.height)
            
# ImageSprite2D class - used for drawing images - sprites
# Very usefull for obtaining gif like animations
class window.ImageSprite2D extends Shape2D
    constructor : (x,y,width,height, spriteRows, spriteCols, spriteWidth,spriteHeight,image) ->
        super        
        @type = "image-sprite-2d"
        @spriteWidth = spriteWidth
        @spriteHeight = spriteHeight
        @spriteRows = spriteRows
        @spriteCols = spriteCols
        @spriteRowIndex = 0
        @spriteColIndex = 0
        # set location and size
        @location.x = x
        @location.y = y
        @size.width = width
        @size.height = height                
        # set the image source
        @changeImage(image)        
    # sets the image source to an Image type or to an image url    
    changeImage : (image) ->
        if typeof image is "object" and image.tagName is "IMG"
            @image = image
        else
            if typeof image is "string"
                self = this
                img = new Image()            
                img.onload = () ->
                    self.image = this
                img.src = image;
            else
                false
    setCurrentSprite : (rowIndex, colIndex) ->
        @spriteRowIndex = rowIndex
        @spriteColIndex = colIndex        
    setSpriteRow : (rowIndex)->
        if rowIndex<@spriteRows and rowIndex>=0
            @spriteRowIndex = rowIndex        
    setSpriteCol : (colIndex)->
        if rowIndex<@spriteCols and colIndex>0
            @spriteColIndex = colIndex        
    setNextSpriteOnRow : ()->
        if @spriteColIndex<@spriteCols-1
            @spriteColIndex++
        else @spriteColIndex = 0         
    setPrevSpriteOnRow : ()->
        if @spriteColIndex>0
            @spriteColIndex--
        else @spriteColIndex = @spriteCols-1        
    #draw the image
    draw : () ->        
        if @image and @context
            @context.drawImage(@image, 
            @spriteWidth * @spriteColIndex,@spriteHeight*@spriteRowIndex,@spriteWidth, @spriteHeight,
            @location.x, @location.y, @size.width, @size.height)
         
# ComposedShape2D - is a class that allow constructing shapes out of subshapes         
# Note that the inner shapes position is relative to the ComposedShape itself.
class window.ComposedShape2D extends Shape2D
    constructor : (x,y) ->
        super
        @type = "composed-2d"
        @location.x = x
        @location.y = y
        @size = 
            width : 0
            height : 0
        @shapes = []
     # add a shape to the composed shape
    add : (shape) ->               
        @shapes.push(shape)        
        @shapes = @shapes.sort( 
            (a,b)->
                if a.zIndex<b.zIndex then 1
                else if a.zIndex>b.zIndex then -1 else 0
        )
        @updateSize()
    # remove a shape from the composed shape  
    remove : (shape) ->
        @shapes.find(
         (elem, index, arr) ->
            if shape is elem
                arr.splice(index,1)
        )
        @updateSize()
    updateSize : () ->
        maxWidth = 0
        maxHeight = 0
        @shapes.each(
             (elem, index, arr) ->
                if elem.location.x + elem.size.width > maxWidth
                    maxWidth = elem.location.x + elem.size.width
                if elem.location.y + elem.size.height > maxHeight
                    maxHeight = elem.location.y + elem.size.height
        )
        @size.width = maxWidth
        @size.height = maxHeight
    # draw the composed shape by drawing the inner shapes
    draw : () ->
        if @context
            self = this
            @shapes.each(
             (elem, index, arr) ->
                oldLocation = 
                    x : elem.location.x
                    y : elem.location.y
                # compute absolute positioning
                elem.move(oldLocation.x + self.location.x, oldLocation.y + self.location.y)
                elem.context = self.context
                elem.draw()
                # revert to relative positioning
                elem.move(oldLocation.x, oldLocation.y)
            )
# Polygon2D - is a class allow for constructing any polygon
class window.Polygon2D extends PolyLine2D
    constructor : (points) ->
        super
        @type = "polygon-2d"
        #make sure we close the polygon        
        if @points.length>1
            firstPoint = @points[0]
            lastPoint  = @points[@points.length-1]
            if  !(firstPoint.x is lastPoint.x and firstPoint.y is lastPoint.y)
                #polygon is not closed
                #we need to close it
                @points.push({
                    x : firstPoint.x,
                    y : firstPoint.y
                } );                
        @position = 
            x:@location.x
            y:@location.y
        @location = (x,y) ->            
            if not x and not y
                @position
            else
                if x
                    dx = x - @position.x
                    @position.x = x
                if y
                    dy = y - @position.y
                    @position.y = y
                @points.each((elem,index,arr)->
                    if x
                        elem.x +=dx
                    if y
                        elem.y +=dy
                )    
    # returns the list of colliding shapes
    # first it initializes with the list of boundary colliding shapes (rectangle intersection)
    # then, for each shape, if that shape qualifies for SAT, it uses that to check if the collision actually occurs
    getCollidingShapes : () -> 
        shapes = super()
        if shapes and shapes.length and shapes.length>0
            self = this            
            newShapes = []
            shapes.each((shape, index, arr)->
                collider = new Polygon2DCollitionSAT(self, shape);
                if collider.collides()
                    newShapes.push(shape)
            )
            shapes = newShapes
        shapes

# Creates a triangle based on polygon class
class window.PolygonTriangle2D extends Polygon2D
    constructor : (x1,y1,x2,y2,x3,y3) ->
        points = [{x:x1,y:y1}, {x:x2, y:y2},{x:x3, y:y3},{x:x1,y:y1}]
        super(points)            

# Creates a rectangle based on polygon class                
class window.PolygonRectangle2D extends Polygon2D
    constructor : (x,y,width,height) ->
        points = [{x:x,y:y}, {x:x+width, y:y},{x:x+width, y:y+width},{x:x,y:y+height},{x:x,y:y}]
        super(points)

# Creates a pentagon based on polygon class
class window.PolygonPentagon2D extends Polygon2D
    constructor : (x,y,l) ->
        points = [];
        point1 = 
            x:x
            y:y
        point2 = 
            x:x          
            y:y+l
        point3 =
            x:point2.x + Math.sin(72*Math.PI/180)*l
            y:point2.y + Math.cos(72*Math.PI/180)*l
        point4 =
            x:point3.x + Math.cos(54*Math.PI/180)*l
            y:point3.y - Math.sin(54*Math.PI/180)*l
        point5 =
            x:point1.x + Math.sin(72*Math.PI/180)*l
            y:point1.y - Math.cos(72*Math.PI/180)*l
        super([point1,point2,point3,point4, point5])

# Creates a hexagon based on polygon class        
class window.PolygonHexagon2D extends Polygon2D
    constructor : (x,y,l) ->
        points = [];
        p1 = 
            x:x
            y:y
        p2 = 
            x: p1.x - Math.cos(30*Math.PI/180)*l
            y: p1.y + Math.sin(30*Math.PI/180)*l
        p3 = 
            x: p2.x
            y: p2.y + l
        p4 = 
            x: p3.x + Math.cos(30*Math.PI/180)*l
            y: p3.y + Math.sin(30*Math.PI/180)*l
        p5 = 
            x: p4.x + Math.cos(30*Math.PI/180)*l
            y: p4.y - Math.sin(30*Math.PI/180)*l
        p6 = 
            x: p5.x
            y: p5.y - l            
        super([p1,p2,p3,p4,p5,p6])

        
# Vector class - used for SAT algorithm
# Supports a few operations on vectors needed for SAT
class window.Vector
    constructor : (@vector) ->        
    substract : (vector) ->
        if not @vector or not @vector.length 
            null
        else
            if not vector or not vector.length or not vector.length is @vector.length
                null
            else
                self = this
                @vector.each((elem,index,arr)->
                    self.vector[index] -= vector[index]
                )
    invert : () ->        
        @vector.each((elem,index,arr)->
            if index < arr.length/2
                #invert with the complement in array
                aux = arr[index]
                arr[index] = arr[arr.length-1-index]
                arr[arr.length-1-index] = aux
        )
    perp : ()->        
        @invert()
        @vector[0] = - @vector[0]
    dotProduct : (vector) ->
        if not @vector or not @vector.length 
            0
        else
            if not vector or not vector.length or not vector.length is @vector.length
                0
            else
                dot = 0
                self = this
                @vector.each((elem,index,arr)->
                    dot += self.vector[index] * vector[index]
                )
                dot

# Class for implementing the SAT based collision detection algorithm
# for now it only works for Polygon2d shapes (shapes derived from polygon2d)
class window.Polygon2DCollitionSAT
    constructor : (@shape1, @shape2) ->
        #valid says if the 2 shapes are valid for collision detection
        #for now both shapes need to be a polygon-2d
        #if valid is not true, when checking for collisions we will say the 2 shapes collide without checking
        @valid = false
        if @shape1.type is "polygon-2d" and @shape2.type is "polygon-2d"
            @valid = true
    # returns the list of projection axes of a polygon shape
    getProjectionAxes : (shape) -> 
        axes = []        
        shape.points.each((elem,index,arr) ->                        
            if not (index is arr.length-1)
                vector1 = new Vector([elem.x,elem.y])
                vector2 = new Vector([arr[index+1].x,arr[index+1].y])
                vector1.substract(vector2.vector)
                vector1.perp()
                axes.push(vector1)
        )
        axes
    # returns the projection of a polygon shape on an axis
    getPolygonProjection : (shape, axis) ->        
        min = axis.dotProduct([shape.points[0].x, shape.points[0].y])
        max = min
        shape.points.each((elem, index, arr)->            
            if index>0                
                val = axis.dotProduct([elem.x, elem.y])
                if min>val
                    min = val
                if max<val
                    max = val
        )
        [min,max]
    # runs the SAT collision algorithm and returns whether the 2 shapes collide or not
    collides : () ->
       
        if not @valid
            true
        else
            self = this
            axes1 = @getProjectionAxes(@shape1)
            axes2 = @getProjectionAxes(@shape2)            
            free = false
            # check for the first axis
            axes1.each((elem,index,arr)->                
                axis = elem                
                p1 = self.getPolygonProjection(self.shape1,axis)
                p2 = self.getPolygonProjection(self.shape2,axis)
                
                #check if p1 and p2 intersect
                overlap = false
                if (p1[0]>p2[0] and p1[0] < p2[1])
                    overlap = true
                if (p2[0]>p1[0] and p2[0] < p1[1])
                    overlap = true
                #if the projections do not overlap, the shapes do not intersect
                if not overlap
                    free = true                
            )
            if not free
                #chek for the second axis
                axes2.each((elem,index,arr)->
                    axis = elem
                    p1 = self.getPolygonProjection(self.shape1,axis)
                    p2 = self.getPolygonProjection(self.shape2,axis)
                
                    #check if p1 and p2 intersect
                    overlap = false
                    if (p1[0]>p2[0] and p1[0] < p2[1])
                        overlap = true
                    if (p2[0]>p1[0] and p2[0] < p1[1])
                        overlap = true
                    if not overlap
                        free = true
                )
            !free